package com.yizisu.playerlibrary.service.download

import android.app.PendingIntent
import android.content.Context
import android.net.Uri
import android.os.Environment
import androidx.annotation.DrawableRes
import com.google.android.exoplayer2.database.ExoDatabaseProvider
import com.google.android.exoplayer2.offline.*
import com.google.android.exoplayer2.ui.DownloadNotificationHelper
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.upstream.HttpDataSource
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
import com.google.android.exoplayer2.upstream.cache.SimpleCache
import com.google.android.exoplayer2.util.Log
import com.google.common.net.HttpHeaders.USER_AGENT
import com.yizisu.playerlibrary.PlayerLibInit
import com.yizisu.playerlibrary.databinding.PlayerLibRcvCacheItemBinding
import com.yizisu.playerlibrary.helper.PlayerModel
import com.yizisu.playerlibrary.impl.exoplayer.getDefaultHttpDataSourceFactory
import com.yizisu.playerlibrary.view.video_view.helper.IPlayerConfig
import com.yizisu.playerlibrary.view.video_view.view.PlayerCacheView
import java.io.File
import java.io.IOException
import java.util.concurrent.Executors


object PlayerDownload {

    data class NotificationUi(
        @DrawableRes var smallIcon: Int,
        var message: String?,
        var contentIntent: PendingIntent?,
    )

    interface NotificationListener : DownloadManager.Listener {
        fun updateNotification(downloads: MutableList<Download>)
    }

    /**
     * NotificationListener监听器
     */
    val notificationListeners by lazy {
        mutableListOf<NotificationListener>()
    }

    /**
     * 拦截点击下载按钮
     */
    var onInterceptCacheClickListener: Function2<PlayerCacheView, IPlayerConfig, Boolean>? =
        null

    /**
     * 最后回调holder设置，可以覆盖默认操作
     */
    var onCacheVideoBindHolderListener: Function3<PlayerLibRcvCacheItemBinding, Download,Boolean, Unit>? =
        null

    /**
     * 通知栏状态更新回调
     */
    var updateNotificationUi: Function1<MutableList<Download>, NotificationUi>? = null

    /**
     * 通知栏id
     */
    var notificationId = 10086

    /**
     * 最大缓存容量
     */
    var maxCache = 100L * 1024 * 1024 * 1024/*100g*/

    /**
     * 通知渠道id
     */
    var channelId = "PlayerDownloadService"

    /**
     * 创建单例缓存对象 SimpleCache
     */
    val simpleCache by lazy {
        val context = PlayerLibInit.app
        SimpleCache(
            File("${context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath ?: context.cacheDir}/exo_cache/"),
            LeastRecentlyUsedCacheEvictor(maxCache),
            ExoDatabaseProvider(context)
        )
    }

    /**
     * 创建单例 DownloadManager
     * 其他参数可以通过此对象来创建
     */
    val downloadManager by lazy {
        val context = PlayerLibInit.app
        val downloadIndex = DefaultDownloadIndex(ExoDatabaseProvider(context))
        upgradeActionFile(
            context, "actions", downloadIndex,  /* addNewDownloadsAsCompleted= */false
        )
        upgradeActionFile(
            context,
            "tracked_actions",
            downloadIndex,  /* addNewDownloadsAsCompleted= */
            true
        )
        DownloadManager(
            context, ExoDatabaseProvider(context),
            simpleCache,
            getDefaultHttpDataSourceFactory(context),
            Executors.newFixedThreadPool(/* nThreads= */ 6)
        ).apply {
            addListener(
                TerminalStateNotificationHelper(
                    context,
                    DownloadNotificationHelper(context, channelId),
                    ++notificationId
                )
            )
        }
    }

    @Synchronized
    private fun upgradeActionFile(
        context: Context,
        fileName: String,
        downloadIndex: DefaultDownloadIndex,
        addNewDownloadsAsCompleted: Boolean
    ) {
        try {
            ActionFileUpgradeUtil.upgradeAndDelete(
                File(
                    context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
                    fileName
                ),  /* downloadIdProvider= */
                null,
                downloadIndex,  /* deleteOnFailure= */
                true,
                addNewDownloadsAsCompleted
            )
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }


    /**
     * 开始下载，已经有任务就恢复下载
     */
    fun startOrResumeDownload(
        model: PlayerModel,
        buildBlock: ((DownloadRequest.Builder) -> Unit)? = null
    ) {
        model.onDownloadUri { uri, id ->
            if (uri != null) {
                val contentId = id ?: uri.toString()
                val download = getDownload(contentId)
                if (download != null) {
                    if (isDownloadCompleted(download)) {
                        //此资源已经下载完成
                        val state = download.state
                    } else {
                        //恢复下载
                        resumeDownload(contentId)
                    }
                } else {
                    //开始下载
                    startDownload(contentId, uri, Download.STOP_REASON_NONE, buildBlock)
                }
            }
        }
    }

    /**
     * 开始下载，已经有任务就恢复下载
     */
    fun startOrResumeDownload(
        contentId: String,
        uri: Uri,
        buildBlock: ((DownloadRequest.Builder) -> Unit)? = null
    ) {
        val download = getDownload(contentId)
        if (download != null) {
            if (isDownloadCompleted(download)) {
                //此资源已经下载完成
                val state = download.state
            } else {
                //恢复下载
                resumeDownload(contentId)
            }
        } else {
            //开始下载
            startDownload(contentId, uri, Download.STOP_REASON_NONE, buildBlock)
        }
    }

    /**
     * 是否下载完成
     */
    fun isDownloadCompleted(download: Download?): Boolean {
        return download?.state == Download.STATE_COMPLETED
    }

    /**
     * 停止下载
     */
    fun startDownload(
        model: PlayerModel,
        stopReason: Int = Download.STOP_REASON_NONE,
        buildBlock: ((DownloadRequest.Builder) -> Unit)? = null
    ) {
        model.onDownloadUri { uri, id ->
            if (uri != null) {
                val contentId = id ?: uri.toString()
                startDownload(contentId, uri, stopReason, buildBlock)
            }
        }
    }

    /**
     * 停止下载
     * stopReason:下载的初始停止原因，如果应该开始下载，则为 {@link DownloadSTOP_REASON_NONE}。
     * 类似于停止下载，给了原因就停止，需要恢复就移除停止原因
     */
    fun startDownload(
        contentId: String,
        uri: Uri,
        stopReason: Int = Download.STOP_REASON_NONE,
        buildBlock: ((DownloadRequest.Builder) -> Unit)? = null
    ) {
        DownloadService.sendAddDownload(
            PlayerLibInit.app,
            PlayerDownloadService::class.java,
            DownloadRequest.Builder(
                contentId, uri
            ).apply {
                buildBlock?.invoke(this)
            }.build(),
            stopReason,
            /* foreground= */ false
        )
    }

    /**
     * 停止下载
     */
    fun stopDownload(model: PlayerModel, stopReason: Int) {
        model.onDownloadUri { uri, id ->
            if (uri != null) {
                val contentId = id ?: uri.toString()
                stopDownload(contentId, stopReason)
            }
        }
    }

    /**
     * 停止下载
     */
    fun stopDownload(contentId: String, stopReason: Int) {
        DownloadService.sendSetStopReason(
            PlayerLibInit.app,
            PlayerDownloadService::class.java,
            contentId,
            stopReason,
            /* foreground= */ false
        )
    }

    /**
     * 恢复下载（设置停止原因是0，即移除停止原因）
     */
    fun resumeDownload(contentId: String) {
        DownloadService.sendSetStopReason(
            PlayerLibInit.app,
            PlayerDownloadService::class.java,
            contentId,
            Download.STOP_REASON_NONE,
            /* foreground= */ false
        )
    }

    /**
     * 恢复下载（设置停止原因是0，即移除停止原因）
     */
    fun resumeDownload(model: PlayerModel) {
        model.onDownloadUri { uri, id ->
            if (uri != null) {
                val contentId = id ?: uri.toString()
                resumeDownload(contentId)
            }
        }
    }

    /**
     * 移除下载
     */
    fun removeDownload(model: PlayerModel) {
        model.onDownloadUri { uri, id ->
            if (uri != null) {
                val contentId = id ?: uri.toString()
                removeDownload(contentId)
            }
        }

    }

    /**
     * 移除下载
     */
    fun removeDownload(contentId: String) {
        DownloadService.sendRemoveDownload(
            PlayerLibInit.app,
            PlayerDownloadService::class.java,
            contentId,
            /* foreground= */ false
        )
    }

    /**
     * 暂停所有下载
     */
    fun pauseAllDownloads() {
        DownloadService.sendPauseDownloads(
            PlayerLibInit.app,
            PlayerDownloadService::class.java,
            /* foreground= */ false
        )
    }

    /**
     * 恢复所有下载
     */
    fun resumeAllDownloads() {
        DownloadService.sendResumeDownloads(
            PlayerLibInit.app,
            PlayerDownloadService::class.java,
            /* foreground= */ false
        )
    }

    /**
     * 根据id获取下载的对象
     */
    fun getDownload(id: String): Download? {
        return downloadManager.downloadIndex.getDownload(id)
    }

    /**
     * 获取所有的下载
     */
    fun getCurrentDownloads(): MutableList<Download> {
        return downloadManager.currentDownloads
    }

    fun getAllDownloads(): MutableList<Download> {
        val tempDownloads = mutableListOf<Download>()
        try {
            downloadManager.downloadIndex.getDownloads(
                Download.STATE_QUEUED,
                Download.STATE_STOPPED,
                Download.STATE_DOWNLOADING,
                Download.STATE_COMPLETED,
                Download.STATE_FAILED,
                Download.STATE_REMOVING,
                Download.STATE_RESTARTING
            ).use { cursor ->
                while (cursor.moveToNext()) {
                    tempDownloads.add(cursor.download)
                }
            }
        } catch (e: IOException) {
            Log.e("", "Failed to load downloads.")
        }
        return tempDownloads
    }

    /**
     * 是否已经在下载任务中
     */
    fun hasDownload(id: String): Boolean {
        return getDownload(id) != null
    }

    fun addNotificationListener(l: NotificationListener) {
        if (!notificationListeners.contains(l)) {
            notificationListeners.add(l)
            downloadManager.addListener(l)
        }
    }

    fun removeNotificationListener(l: NotificationListener) {
        notificationListeners.remove(l)
        downloadManager.removeListener(l)
    }
}